home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Libraries / grayimage / endian_io.cc < prev    next >
Encoding:
Text File  |  1994-06-30  |  5.0 KB  |  180 lines  |  [TEXT/R*ch]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *            Modified File class
  6.  *    to read integers of various sizes taking the byte order
  7.  *                into account
  8.  *              and bit-stream IO
  9.  *
  10.  ************************************************************************
  11.  */
  12.  
  13. #pragma implementation
  14. #include "endian_io.h"
  15. #include <unistd.h>
  16. #include <errno.h>
  17.  
  18.  
  19. /*
  20.  *------------------------------------------------------------------------
  21.  *               Error handling
  22.  */
  23.  
  24. void EndianIO::error(const char *descr)
  25. {
  26.   if( eof() )
  27.     _error("'%s' failed because of the End-Of-File",descr);
  28.   perror(descr);
  29.   _error("Aborted due to the I/O error above");
  30. }
  31.  
  32. /*
  33.  *------------------------------------------------------------------------
  34.  *            Opening/closing
  35.  *
  36.  * Note that when the EndianIO stream is opened by example, 
  37.  * it shares the i/o buffer with the existing stream. Care should be taken
  38.  * to not destroy the buffer when the attached stream is closed/destroyed.
  39.  * The situation is similar to what happens when a file handle is
  40.  * duplicated with the system function dup(). Note that creating a new
  41.  * file buffer for the attached stream based on the dup()-ed file
  42.  * handle is not enough. Indeed, the old (sample) stream could've read
  43.  * some data ahead in it's buffer, so the system file pointer would not
  44.  * correspond to data that were actually read (and consumed) by the
  45.  * user. Though this situation can be remedied using a fstream.sync()
  46.  * function (which sets the system file pointer to correspond to what
  47.  * actually was read from the stream and discards the read-ahead data)
  48.  * when the attached stream read from the file and advances the file
  49.  * pointer, the old file should be able to recognized that fact that
  50.  * the file was read by another stream. This problem cannot be solved
  51.  * withoud sharing the file buffer.
  52.  */
  53.                     // Open by example at the time
  54.                     // of constructing EndianIO stream
  55. EndianIO::EndianIO(EndianIO& a_file)
  56.     : fstream()
  57. {
  58.   open(a_file);
  59. }
  60.  
  61.                     // Deferred opening by example
  62. EndianIO& EndianIO::open(EndianIO& a_file)
  63. {
  64. #if 0            // Because of the stupid implementation of filebuf:
  65.   if( rdbuf() )        // filebuf is a part of the class fstream in GCC
  66.     delete rdbuf();        // Destroy the old stream buffer
  67. #endif
  68.   _strbuf = a_file.rdbuf();        // Share the buffer of a_file
  69.   byte_order = a_file.byte_order;
  70.   setf(ios::dont_close | attached);
  71. //  setf(attached);
  72.   clear();
  73.   return *this;
  74. }
  75.  
  76.                 // The sole purpose of this function to
  77.                 // leave the stream open when it is attached
  78. void EndianIO::close(void)
  79. {
  80.   if( (flags() & attached) != attached )
  81.     fstream::close();
  82. }
  83.  
  84.                 // If the stream was attached, detach it
  85.                 // from the buffer
  86. EndianIO::~EndianIO(void)
  87. {
  88.   if( (flags() & attached) == attached )
  89.     _strbuf = 0;
  90. }
  91.  
  92. /*
  93.  *------------------------------------------------------------------------
  94.  *               Reading routines
  95.  */
  96.  
  97.                 // Read a SHORT (2 bytes) datum item
  98.                 // in the specified byte_order
  99. unsigned short int EndianIO::read_short(const char * op_description)
  100. {
  101.   unsigned char c1, c2;
  102.  
  103.   if( !get(c1) || !get(c2) ) // Read 2 consecutive bytes
  104.     error(op_description);
  105.  
  106.   if( byte_order == MSBfirst )
  107.     return (c1 << 8) | c2;
  108.   else
  109.     return (c2 << 8) | c1;
  110. }
  111.  
  112.                 // Read a LONG (4 bytes) datum item
  113.                 // in the specified byte_order
  114. unsigned long int EndianIO::read_long(const char * op_description)
  115. {
  116.   unsigned char c1, c2, c3, c4;
  117.  
  118.   if( !get(c1) || !get(c2) ||             // Read 4 consecutive bytes
  119.       !get(c3) || !get(c4) )
  120.     error(op_description);
  121.  
  122.   if ( byte_order == MSBfirst )
  123.     return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
  124.   else
  125.     return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1;
  126. }
  127.  
  128.  
  129. /*
  130.  *------------------------------------------------------------------------
  131.  *            Service writing routines
  132.  */
  133.  
  134. void EndianIO::write_byte
  135.     (const int item, const char * op_description = "")
  136. {
  137.   if( !put(item) )
  138.     error(op_description);
  139. }
  140.  
  141.                 // Write out a short item as specified by
  142.                 // the byte_order
  143. void EndianIO::write_short
  144.     (const unsigned short item, const char* op_description = "")
  145. {
  146. #if 0                    // The following does NOT work
  147.   union {                // because it doesn't make sure
  148.     unsigned short int short_int;    // that c2 follows c1
  149.     struct { unsigned char c1,c2; } bytes;
  150.   } int_bytes;
  151.   int_bytes.short_int = item;
  152.   write_byte(int_bytes.bytes.c2,"write_short, 2nd byte");
  153.   write_byte(int_bytes.bytes.c1,"write_short, 1st byte");
  154. #endif
  155.   if( byte_order == MSBfirst )
  156.     write_byte((item>>8) & 0xff,"write_short, hi byte"),
  157.     write_byte(item & 0xff,"write_short, lo byte");
  158.   else
  159.     write_byte(item & 0xff,"write_short, lo byte"),
  160.     write_byte((item>>8) & 0xff,"write_short, hi byte");
  161. }
  162.  
  163.  
  164.                 // Write out a long item as specified by
  165.                 // the byte_order
  166. void EndianIO::write_long
  167.     (const unsigned long item, const char * op_description = "")
  168. {
  169.   register unsigned int t = item;
  170.   register int i;
  171.  
  172.   if( byte_order == MSBfirst )
  173.     for(i=24; i>=0; i-=8)
  174.       write_byte((t >> i) & 0xff,"write_long");
  175.   else
  176.     for(i=0; i<4; i++)
  177.       write_byte(t & 0xff,"write_long"), t >>= 8;
  178. }
  179.  
  180.